/**
  ******************************************************************************
  * @file           : ECCOperator.h
  * @author         : sally
  * @brief          : None
  * @attention      : None
  * @date           : 24-11-11
  ******************************************************************************
  */



#ifndef ECCOPER_H
#define ECCOPER_H

#include <cstddef>
#include <iostream>
#include <memory>
#include <openssl/bn.h>
#include <openssl/ec.h>
#include <openssl/err.h>
#include <openssl/obj_mac.h>
#include <openssl/types.h>
#include <vector>
#include "Deleter.h"

namespace droneswarm
{

    constexpr int salt_length = 16;
    constexpr int salt_hash_length = 32;
    // static EC_KEY *eckey;
    // const EC_GROUP *ec_group;
    //设计成一个类吗？
    /*
        描述一条Z*q上的椭圆曲线，常用到六个参数：
        T=(q,a,b,G,order,h)。
        q 、a 、b 用来确定一条椭圆曲线，
        G为基点，
        order为点G的阶，
        我们事先指定好了一个国际上通用的安全曲线:NID_X9_62_prime256v1曲线
        ECC公钥加密一般使用的是混合加密方式，因为椭圆曲线加密ECC主要用来密钥交换和数字签名，并不用来直接加密数据。因为效率较低，且加密的数据较低，且加密数据的数据长度会非常长。
        因此采用的是一种成为椭圆曲线集成加密方案(ECIES)的方法。他结合了对称加密和椭圆曲线加密的优点。
        ECIES 的工作原理如下：
        1：生成随机对称密钥：使用椭圆曲线 Diffie-Hellman（ECDH）算法生成一个随机的对称密钥。
        2：加密数据：使用对称密钥（如 AES）加密数据。
        3：加密对称密钥：使用接收者的公钥加密对称密钥。
        5：传输密文和加密的对称密钥：发送给接收者。
    */

    //定义删除器

    unsigned char *generate_salt( size_t length );
    std::string base64_encode( const unsigned char *data, size_t length );
    enum Model
    {
        ONLYGETPRIKEY,
        ONLYGETPUBKEY,
        GETBOTH
    };

    class ECCOperator
    {
    public:
        ECCOperator();
        ~ECCOperator();

        BIGNUM *getPrime() { return q_; }
        BIGNUM *getOrder() { return n_; }
        BIGNUM *getXCoordinate() { return XP_; }
        BIGNUM *getYCoordinate() { return YP_; }
        BIGNUM *getCofactor() { return h_; }
        BIGNUM *geta() { return a_; }
        BIGNUM *getb() { return b_; }
        BN_CTX *getCtx() { return ctx_; }
        EC_GROUP *getGroup() { return curveAttributes_; }

        std::shared_ptr< BIGNUM > GeneratePriKey();
        EC_POINT *getBasePoint() { return P_; }
        std::shared_ptr< EC_POINT > GeneratePubKey( BIGNUM *PriKey );
        int BN_ECKey_Conv_EC_EVPKey( BIGNUM *k_priv, EC_POINT *k_pub, EC_GROUP *group, EVP_PKEY **out_evp_pkey );
        int ECPubKey_Conv_EVPPubKey( EC_POINT *k_pub, EC_GROUP *group, EVP_PKEY **out_evp_pubkey );
        std::shared_ptr< unsigned char > EC_POINT2Char( EC_POINT *point, point_conversion_form_t form );
        int deriveSymmetricKey( const EC_GROUP *group,
                                const EC_POINT *pub_key,
                                BIGNUM *priv_key,
                                unsigned char *salt,
                                unsigned char *out_key );
        // void setSalt( unsigned char *s ) { salt_ = s; }
        // unsigned char *getSalt() { return salt_; }
        // unsigned char *getSaltHash() { return saltHash_; }

        //对盐值进行哈希

        void setSaltHash();

        //接下来需要写将EVP_PKEY提取成BIGNUM和EC_POINT类型的数据
        bool extract_Pub_Priv_Frome_EVP_PKEY( EVP_PKEY *pkey, BIGNUM **priv, EC_POINT **pub, Model model );

        //使用EVP_PKEY数据来进行数字签名
        std::string generateESDSASignature( EVP_PKEY *priKey, const std::string rawData );
        bool verifyEDSAsignature( EVP_PKEY *pubkey, const std::string &rawData, const std::string &signData );
        bool computeSessionKey(EVP_PKEY *myPriKey,EVP_PKEY *peerPubKey,unsigned char ** sessionKey);

    private:
        void handleOpenSSLErrors() { ERR_print_errors_fp( stderr ); }

    private:
        BIGNUM *q_;  //这是椭圆曲线的安全素数
        BIGNUM *n_;  //这是椭圆曲线的子群的阶
        BIGNUM *a_;
        BIGNUM *b_;
        EC_POINT *P_;                //这是椭圆曲线的基点
        EC_GROUP *curveAttributes_;  //这是椭圆曲线的相关属性
        // EC_GROUP *不是加法群的结构，而是该椭圆曲线的所以参数都保存在这个结构体中。
        BIGNUM *XP_;   //这是基点和横坐标
        BIGNUM *YP_;   //这是基点的纵坐标
        BIGNUM *h_;    //这是曲线的协同因子
        BN_CTX *ctx_;  // OpenSSL 中的一个结构体指针，用于管理 BIGNUM 操作的临时内存空间。
        //使用q来生成q阶的椭圆曲线加法群G。
        // unsigned char *salt_;
        // unsigned char *saltHash_;
    };

}  // namespace droneswarm



#endif //ECCOPER_H
